package com.scs.application.modules.wm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.entity.DataEntity;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.pdf.PdfExportUtils;
import com.scs.application.core.pdf.entity.PdfExportGridIndexColumn;
import com.scs.application.core.pdf.entity.PdfExportParams;
import com.scs.application.core.pdf.enums.PdfPageDirection;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.mapper.SupplierMapper;
import com.scs.application.modules.base.service.DeptService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.base.util.MatrPassUtil;
import com.scs.application.modules.base.util.SingleService;
import com.scs.application.modules.cfg.utils.ParameterUtils;
import com.scs.application.modules.dept.entity.Apply;
import com.scs.application.modules.dept.entity.ApplyAuto;
import com.scs.application.modules.dept.entity.ApplyAutoHistory;
import com.scs.application.modules.dept.entity.Demand;
import com.scs.application.modules.dept.service.ApplyAutoHistoryService;
import com.scs.application.modules.dept.service.ApplyAutoService;
import com.scs.application.modules.dept.service.ApplyService;
import com.scs.application.modules.dept.service.DemandService;
import com.scs.application.modules.dept.util.UtilBudget;
import com.scs.application.modules.purchase.entity.Order;
import com.scs.application.modules.purchase.enums.PurchaseType;
import com.scs.application.modules.purchase.service.OrderService;
import com.scs.application.modules.wm.dto.DistDTO;
import com.scs.application.modules.wm.dto.PickDTO;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.enums.LockBusType;
import com.scs.application.modules.wm.enums.UniqueCodeType;
import com.scs.application.modules.wm.enums.WorkOrderType;
import com.scs.application.modules.wm.mapper.DistMapper;
import com.scs.application.modules.wm.mapper.PickItemMapper;
import com.scs.application.modules.wm.mapper.WorkOrderItemMapper;
import com.scs.application.modules.wm.mapper.WorkOrderMapper;
import com.scs.application.modules.wm.service.*;
import com.scs.application.modules.wm.vo.DistVO;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
public class DistServiceImpl extends BaseServiceImpl<DistMapper, Dist> implements DistService {
    @Value("${res.real-path}")
    private String resPath;

    @Autowired
    private StockLockService stockLockService;

    @Autowired
    private StockService stockService;

    @Autowired
    private PickItemMapper pickItemMapper;

    @Autowired
    private PickItemService pickItemService;

    @Autowired
    private WorkOrderMapper workOrderMapper;

    @Autowired
    private WorkOrderItemMapper workOrderItemMapper;

    @Autowired
    private SupplierMapper supplierMapper;

    @Autowired
    private WorkOrderService workOrderService;

    @Autowired
    private WorkOrderItemService workOrderItemService;

    @Autowired
    private ApplyAutoHistoryService applyAutoHistoryService;

    @Autowired
    private ApplyAutoService applyAutoService;

    @Autowired
    DistItemService distItemService;


    @Autowired
    private OrderService orderService;

    @Autowired
    private DeptService deptService;

    @Autowired
    private DemandService demandService;

    @Autowired
    private ApplyService applyService;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private MatrPassUtil matrPassUtil;

    @Override
    public boolean saveOrUpdate(Dist entity) {
        if (StringUtils.isBlank(entity.getBusKey())) {
            entity.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.WM_DIST_KEY));
        }
        super.saveOrUpdate(entity);
        Dept dept = deptService.getById(entity.getDeptId());
        if (dept != null)entity.setDeptAddressName(dept.getAddressName());

        return true;
    }

    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        List<DistItem> distItems = distItemService.list(Wrappers.<DistItem>query().in("dist_id", idList));
        if (distItems != null && distItems.size() > 0) {
            distItemService.removeCascadeByIds(distItems.stream().map(DistItem::getId).collect(Collectors.toList()));
        }

        //更新关联入库单的关联ID
        workOrderMapper.update(null,Wrappers.<WorkOrder>update()
                .in("ref_dist_id", idList)
                .set("ref_dist_id", null));
        return super.removeCascadeByIds(idList);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    synchronized public void pick(String distId, String uniqueCode) {
        List<PickDTO> pickDTOs = new ArrayList<>();
        PickDTO pickDTO = new PickDTO();
        pickDTO.setDistId(distId);
        pickDTO.setUniqueCode(uniqueCode);
        pickDTOs.add(pickDTO);

        this.pickBatch(pickDTOs);

       /* Dist dist = this.getById(distId);
        if (dist == null) {
            throw new BusinessException("配送单不存在");
        }

        Stock stock = stockService.getStockByUniqueCode(uniqueCode);
        if (stock == null) {
            throw new BusinessException(String.format("在库存中未找到%s相关的耗材", uniqueCode));
        }

        if (!stock.getWarehouseId().equalsIgnoreCase(dist.getWarehouseId())) {
            throw new BusinessException("当前耗材处于%s，与配送仓库%s不一致，不支持拣货", stock.getWarehouseName(), dist.getWarehouseName());
        }


        if (stock.getFlagOmoc()) {
            throw new BusinessException("当前耗材为一物一码耗材，不支持添加到配送单中", stock.getWarehouseName(), dist.getWarehouseName());
        }

        // 通过配送的方式，如果之前有进行锁库，先进行虚拟解锁
        // 请领是否锁库存
        boolean applyLock = ParameterUtils.isApplyLockStock();
        String matrId = stock.getMatrId();
        if (applyLock) {
            List<DistItem> distItems = distItemService.list(new QueryWrapper<DistItem>().eq("dist_id", distId).eq("matr_id", matrId).isNotNull("apply_item_id"));
            if (distItems != null && distItems.size() > 0) {
                unLockApplyVirtual(stock.getSkuQty(), distItems.stream().map(DistItem::getApplyItemId).collect(Collectors.toList()), dist.getWarehouseId());
            }
        }
        // 尝试锁定库存
        String busKey = dist.getBusKey();
        UniqueCodeType uniqueCodeType = UniqueCodeUtils.getUniqueCodeType(uniqueCode);
        stockLockService.lock(LockBusType.DIST, distId,
                dist.getWarehouseId(), uniqueCode, uniqueCodeType,
                String.format("配送单 %s 拣货锁定", busKey));
        DistItem distItem = pickRefDistItem(stock, distId);
        // 增加拣货明细
        PickItem pickItem = new PickItem();
        pickItem.setDistId(dist.getId()).setDistItemId(distItem.getId()).setStockId(stock.getId())
                .setMatrId(matrId).setMatrName(stock.getMatrName()).setMatrSpec(stock.getMatrSpec())
                .setPackageUnit(stock.getPackageUnit()).setPackageRate(stock.getSkuQty() / stock.getPackageQty()).setPackageQty(stock.getPackageQty())
                .setSkuUnit(stock.getSkuUnit()).setSkuPrice(stock.getSkuPrice()).setSkuQty(stock.getSkuQty())
                .setAmount(stock.getAmount()).setCertificateNo(stock.getCertificateNo()).setMfgName(stock.getMfgName())
                .setLot(stock.getLot()).setExpDate(stock.getExpDate()).setMfgDate(stock.getMfgDate())
                .setSn(stock.getSn()).setUdi(stock.getUdi()).setRfid(stock.getRfid()).setUcType(uniqueCodeType.name())
                .setSupplierId(stock.getSupplierId()).setSupplierName(stock.getSupplierName())
                .setRemark(String.format("配送单 %s 拣货", busKey));
        pickItemMapper.insert(pickItem);

        DistDTO distDTO = baseMapper.getDistAmountAndPick(distId);
        Double demandsSum = baseMapper.getDistDemand(distId);
        String pickAndDemand = UtilNum.getString(distDTO.getPickQty()) + "-/-" + UtilNum.getString(demandsSum);
        baseMapper.calculateDistInfo(distId, pickAndDemand, distDTO.getAmount());


        //更新需求明细状态
        CommonService.updateApplyItemStatus(distItem.getApplyItemId(), false, null);*/
    }

    /**
     * 拣货解锁虚拟锁
     *
     * @param stockSkuQty 扫描库存单品数量
     * @param busKeys
     * @param warehouseId
     */
    private void unLockApplyVirtual(Double stockSkuQty, List<String> busKeys, String warehouseId) {
        for (int i = 0; i < busKeys.size(); i++) {
            if (stockSkuQty < 0) {
                break;
            }
            String busKey = busKeys.get(i);
            StockLock stockLock = stockLockService.getVirtualLock(LockBusType.APPLY, busKey, warehouseId);
            if (stockLock != null && stockLock.getQty() > 0) {
                if (stockSkuQty < stockLock.getQty()) { //如果小于虚拟锁数量，直接减去即可
                    stockLockService.reduceVirtualLock(LockBusType.APPLY, busKey, warehouseId, stockSkuQty);
                    break;
                } else if (stockSkuQty == stockLock.getQty()) { //恰好相等，解除虚拟锁
                    stockLockService.virtualUnlock(LockBusType.APPLY, busKey, warehouseId);
                    break;
                } else { //不够解锁的，再循环
                    stockLockService.virtualUnlock(LockBusType.APPLY, busKey, warehouseId);
                    stockSkuQty -= stockLock.getQty();
                }
            }
        }
    }

    /**
     * 取消拣货加锁虚拟锁
     *
     * @param distItem
     * @param warehouseId
     */
    private void lockApplyVirtual(DistItem distItem, String warehouseId, Double stockSkuQty) {
        String busKey = distItem.getApplyItemId();
        StockLock stockLock = stockLockService.getVirtualLock(LockBusType.APPLY, busKey, warehouseId);
        if (stockLock != null) { //加上锁的数量
            if (distItem.getSkuQty() > stockLock.getQty() + stockSkuQty) {
                stockLockService.reduceVirtualLock(LockBusType.APPLY, busKey, warehouseId, -stockSkuQty);
                stockSkuQty = 0d;
            } else if (distItem.getSkuQty() > stockLock.getQty()) {
                stockSkuQty -= distItem.getSkuQty() - stockLock.getQty();
                stockLockService.reduceVirtualLock(LockBusType.APPLY, busKey, warehouseId, stockLock.getQty() - distItem.getSkuQty());
            }
        } else {
            Double moreSkuQty = distItem.getPickedSkuQty() - distItem.getSkuQty(); //多拣的
            if (moreSkuQty > 0) {
                stockSkuQty -= moreSkuQty;
            }
            if (stockSkuQty <= 0) {
                return;
            }
            stockLockService.virtualLock(LockBusType.APPLY, busKey, warehouseId, distItem.getMatrId(), distItem.getSkuQty() > stockSkuQty ? stockSkuQty : distItem.getSkuQty());
            stockSkuQty -= distItem.getSkuQty();
        }
        if (stockSkuQty <= 0) {
            return;
        }
        //考虑一种情况，两个同样的耗材，一个包装满足两个
        List<DistItem> otherDistItems = distItemService.list(new QueryWrapper<DistItem>()
                .eq("dist_id", distItem.getDistId())
                .eq("matr_id", distItem.getMatrId())
                .gt("picked_sku_qty", 0)
                .isNotNull("apply_item_id"));

        if (otherDistItems != null && otherDistItems.size() > 0) {
            for (int i = 0; i < otherDistItems.size(); i++) {
                if (otherDistItems.get(i).getId().equals(distItem.getId())) {
                    if (i > 0) {
                        lockApplyVirtual(otherDistItems.get(i - 1), warehouseId, stockSkuQty);
                    }
                    break;
                }
            }
        }
    }

    /**
     * 拣货影响配送单操作
     *
     * @return
     */
    private DistItem pickRefDistItem(Stock stock, String distId) {
        List<DistItem> distItems = distItemService.list(Wrappers.<DistItem>query().eq("dist_id", distId).eq("matr_id", stock.getMatrId()));
        DistItem distItem = null;
        Double stockSkuQty = stock.getSkuQty(); //拣货的单品数量
        List<DistItem> needUpdateDistItems = Lists.newArrayListWithCapacity(distItems.size());
        if (distItems != null && distItems.size() > 0) {
            for (int i = 0; i < distItems.size(); i++) {
                if (stockSkuQty <= 0) {
                    break;
                }
                DistItem distItem1 = distItems.get(i);
                if (distItem1.getPickedSkuQty() < distItem1.getSkuQty()) { //拣货数量小于单品数量
                    if (Double.compare(Double.sum(distItem1.getPickedSkuQty(), stockSkuQty), distItem1.getSkuQty()) == 1) { //如果加上库存数量大于了原定拣货数量时
                        stockSkuQty = Double.sum(distItem1.getPickedSkuQty(), stockSkuQty) - distItem1.getSkuQty();
                        distItem1.setPickedSkuQty(distItem1.getSkuQty())
                                .setPickedAmount(distItem1.getSkuQty() * stock.getSkuPrice());
                        if (i < distItems.size() - 1) {
                            needUpdateDistItems.add(distItem1);
                        }
                    } else {
                        distItem1.setPickedSkuQty(Double.sum(distItem1.getPickedSkuQty(), stockSkuQty));
                        distItem1.setPickedAmount(distItem1.getPickedSkuQty() * stock.getSkuPrice());
                        needUpdateDistItems.add(distItem1);
                        stockSkuQty = 0d;
                    }
                }

                if (stockSkuQty > 0 && i == distItems.size() - 1) { //如果多拣了，放在最后一条累加
                    distItem1.setPickedSkuQty(Double.sum(distItem1.getPickedSkuQty(), stockSkuQty));
                    distItem1.setPickedAmount(distItem1.getPickedSkuQty() * stock.getSkuPrice());
                    needUpdateDistItems.add(distItem1);
                }
            }
        }
        if (needUpdateDistItems != null && needUpdateDistItems.size() > 0) {
            //更新配送需求金额
            needUpdateDistItems.forEach(item -> {
                Double distItemAmount = BigDecimal.valueOf(item.getSkuPrice() * item.getPickedSkuQty()).setScale(2,  BigDecimal.ROUND_HALF_UP).doubleValue();
                item.setAmount(distItemAmount);
            });
            // 更新已拣货SKU数量
            distItemService.saveOrUpdateBatch(needUpdateDistItems);
            distItem = needUpdateDistItems.get(needUpdateDistItems.size() - 1);
        } else {// 拣货时允许拣选当前配送单中不存在的耗材
            // 新增配送明细
            distItem = new DistItem();
            BeanUtils.copyProperties(stock, distItem);
            distItem.setId(null);
            distItem.setDistId(distId).setApplyItemId(null)
                    .setMatrId(stock.getMatrId()).setMatrName(stock.getMatrName()).setMatrSpec(stock.getMatrSpec())
                    .setPackageUnit(stock.getPackageUnit()).setPackageRate(stock.getSkuQty() / stock.getPackageQty()).setPackageQty(0.0)
                    .setSkuUnit(stock.getSkuUnit()).setSkuPrice(stock.getSkuPrice()).setSkuQty(0.0)
                    .setPickedSkuQty(stock.getSkuQty())
                    .setRemark(String.format("由拣货自动新增"));
            Double distItemAmount = BigDecimal.valueOf(distItem.getSkuPrice() * distItem.getPickedSkuQty()).setScale(2,  BigDecimal.ROUND_HALF_UP).doubleValue();
            distItem.setAmount(distItemAmount);
            distItemService.save(distItem);
        }
        return distItem;
    }

    /**
     * 取消拣货影响配送单操作
     *
     * @return
     */
    private void unPickRefDistItem(DistItem distItem, PickItem pickItem, String distId, Double unPickSkqQty) {
        if (unPickSkqQty <= 0) {
            return;
        }
        if (distItem.getPickedSkuQty() >= unPickSkqQty) { //已拣货数量大于取消拣货的值，直接减即可
            distItem.setPickedSkuQty(distItem.getPickedSkuQty() - unPickSkqQty);
            Double distItemAmount = BigDecimal.valueOf(distItem.getPickedSkuQty() * pickItem.getSkuPrice()).setScale(2,  BigDecimal.ROUND_HALF_UP).doubleValue();
            distItem.setAmount(distItemAmount);
            distItemService.updateCascadeById(distItem);
            return;
        } else { //先把该配送单设置未拣货0，再去找上一个配送单，减上一个的
            unPickSkqQty = unPickSkqQty - distItem.getPickedSkuQty();
            //先置当前的拣货数量为空
            distItem.setPickedSkuQty(0d).setPickedAmount(0d);
            distItemService.updateCascadeById(distItem);

            List<DistItem> otherDistItems = distItemService.list(new QueryWrapper<DistItem>()
                    .eq("dist_id", distId)
                    .eq("matr_id", pickItem.getMatrId())
                    .ne("id", pickItem.getDistItemId())
                    .gt("picked_sku_qty", 0)
                    .isNotNull("apply_item_id"));
            if (otherDistItems != null && otherDistItems.size() > 0) {
                DistItem distItem1 = otherDistItems.get(otherDistItems.size() - 1);
                unPickRefDistItem(distItem1, pickItem, distId, unPickSkqQty);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    synchronized public void unpick(List<String> pickItemIdList) {
        if (pickItemIdList.isEmpty()) {
            return;
        }
        List<PickItem> pickItems = pickItemMapper.selectBatchIds(pickItemIdList);
        List<String> distIdList = pickItems.stream().map(PickItem::getDistId).distinct().collect(Collectors.toList());
        List<Dist> distList = this.list(Wrappers.<Dist>query().in("id",distIdList));
        if (distList == null || distList.size() < 1) throw new BusinessException("对应配送单不存在或者已删除");

        // 解锁实际库存
        stockLockService.unlockBatch(pickItems.stream().map(PickItem::getSn).collect(Collectors.toList()));

        for (PickItem pickItem : pickItems) {
            String distItemId = pickItem.getDistItemId();
            DistItem distItem = distItemService.getById(distItemId);
            if (distItem == null)   throw new BusinessException("对应拣货明细不存在或者已删除");

            Dist dist = distList.stream().filter(distTmp -> distTmp.getId().equals(distItem.getDistId())).findAny().orElse(null);
            if (dist == null)  throw new BusinessException("对应配送单不存在或者已删除");

            // 增加虚拟锁
            boolean applyLock = ParameterUtils.isApplyLockStock();
            if (applyLock && StringUtils.isNotBlank(distItem.getApplyItemId())) {
                lockApplyVirtual(distItem, dist.getWarehouseId(), pickItem.getSkuQty());
            }
            pickItemMapper.deleteById(pickItem.getId());

            // 更新已拣货SKU数量
            unPickRefDistItem(distItem, pickItem, distItem.getDistId(), pickItem.getSkuQty());

//            取消拣货，删除已拣货SKU数量为0的 拣货自动添加,没有请领关系 的删除
            if (StringUtils.isBlank(distItem.getApplyItemId()) && distItem.getPickedSkuQty() == 0) {
                List<String> list = Collections.singletonList(distItem.getId());
                distItemService.removeCascadeByIds(list);
            }

            //更新需求明细状态
            CommonService.updateApplyItemStatus(distItem.getApplyItemId(), false, null);

        }

        //更新金额
        distIdList.stream().forEach(distId -> {
            DistDTO distDTO = baseMapper.getDistAmountAndPick(distId);
            Double demandsSum = baseMapper.getDistDemand(distId);
            String pickAndDemand = UtilNum.getString(distDTO.getPickQty()) + "-/-" + UtilNum.getString(demandsSum);
            String distType = distDTO.getPickQty() == 0 ? PurchaseType.MATR.getKey() : null;
            baseMapper.calculateDistInfo(distId, pickAndDemand, distDTO.getAmount(), distType);
        });
    }

    @Override
    protected void beforeHandleFlowChange(FlowContext flowContext, Dist newEntity) {
        super.beforeHandleFlowChange(flowContext, newEntity);
        String buttonKey = flowContext.getButtonKey();

        Dist dist = flowContext.getBusEntity();


        //提交操作
        if ("submit".equalsIgnoreCase(buttonKey)) {
            //自动科室需求、手工科室需求需要包含需求明细
            if (GlobalConsts.DistTransferSourceType.DEPT_APPLY_AUTO.equals(dist.getSourceType()) || GlobalConsts.DistTransferSourceType.DEPT_APPLY.equals(dist.getSourceType())) {
                int itemSize = distItemService.count(Wrappers.<DistItem>query().eq("dist_id", dist.getId()));
                if (itemSize < 1) throw new BusinessException("当前单据需要先手动创建需求，请添加好需求再提交");
            };
        }


        // 审核，不允许空明细审核
        if ("pass".equalsIgnoreCase(buttonKey)) {
            /*Integer count = pickItemMapper.selectCount(Wrappers.<PickItem>query().eq("dist_id", flowContext.getBusId()));
            if (count == null || count == 0) {
                throw new BusinessException("请先进行拣货");
            }*/
        }
//        拣货完成操作
        if ("dist".equalsIgnoreCase(buttonKey)) {
            Integer count = pickItemMapper.selectCount(Wrappers.<PickItem>query().eq("dist_id", flowContext.getBusId()));
            if (count == null || count == 0) {
                throw new BusinessException("请先完成所有配送明细拣货操作");
            }
//            开始配送强制修复金额
            List<PickItem> pickItemList = pickItemMapper
                    .selectList(Wrappers.<PickItem>query().eq("dist_id", flowContext.getBusId()));
            pickItemList.forEach(ob -> {
                //单品数量*单品价格 是否等于 合计金额
                if(UtilNum.mul(ob.getSkuQty(),ob.getSkuPrice()) != ob.getAmount())  {
                    ob.setAmount(UtilNum.mul(ob.getSkuQty(),ob.getSkuPrice()));
                    //单品数量*单品价格 是否等于 合计金额
                    pickItemMapper.updateById(ob);
                }
            });

            final double[] amountDtl = {0};
            pickItemList.forEach(item -> amountDtl[0] =UtilNum.sum(amountDtl[0],item.getAmount()));
            Dist distDb = this.getById(newEntity.getId());
            if (amountDtl[0] != distDb.getAmount()) {
                distDb.setAmount(amountDtl[0]);
                this.updateById(distDb);
            }
        }
        //        开始拣货更新状态
        if ("start_pick".equalsIgnoreCase(buttonKey)) {
            dist.setStatusPick(1).setPicker(dist.getFlowModifier()).setPickDate(dist.getFlowModified() == null ? DateUtils.now() :DateUtils.localDateTime2Date(dist.getFlowModified()));
            this.updateCascadeById(dist);
        }
//        拣货完成更新状态
        if ("end_pick".equalsIgnoreCase(buttonKey)) {
            dist.setStatusPick(2).setPickDate(DateUtils.localDateTime2Date(dist.getFlowModified() == null ? LocalDateTime.now() : dist.getFlowModified() ));
            this.updateCascadeById(dist);
        }
//        取消配送
        if ("cancel_dist".equalsIgnoreCase(buttonKey)) {
            List<String> pickItemIds = pickItemMapper
                    .selectList(Wrappers.<PickItem>query().eq("dist_id", flowContext.getBusId()))
                    .stream().map(PickItem::getId).collect(Collectors.toList());
            unpick(pickItemIds);
            dist.setStatusPick(0).setPickDate(null).setPicker(null).setAmount(0D);
            this.updateCascadeById(dist);
            List<DistItem> distItems = distItemService.list(Wrappers.<DistItem>query().eq("dist_id", dist.getId()));

            for (DistItem distItem : distItems) {
                if (StringUtils.isNotBlank(distItem.getApplyItemId())) {
                    Double sumPickQty = distItemService.getObj(Wrappers.<DistItem>query().select("ifnull(sum(picked_sku_qty),0.0)").eq("apply_item_id", distItem.getApplyItemId()), v -> {
                        if (v == null) {
                            return 0.0;
                        }
                        return Double.valueOf(v.toString());
                    });
                    applyAutoService.update(Wrappers.<ApplyAuto>update().set("picked_sku_qty", sumPickQty)
                            .eq("ref_apply_item_id", distItem.getApplyItemId()));
                }
            }
        }
    }

    @Override
    protected void afterHandleFlowChange(FlowContext flowContext, Dist newEntity) {
        super.afterHandleFlowChange(flowContext, newEntity);
        String buttonKey = flowContext.getButtonKey();
        // 如果是结束节点，依据拣货明细创建出库单
        Dist dist = flowContext.getBusEntity();

        List<DistItem> distItems = distItemService.list(Wrappers.<DistItem>query().eq("dist_id", dist.getId()));
        List<ApplyAuto> applyAutoList = applyAutoService.list(new QueryWrapper<ApplyAuto>().eq("ref_id", dist.getId()));

        //流程节点校验耗材
        matrPassUtil.ckeckMatrPass("dist",distItems.stream().map(DistItem::getMatrId).collect(Collectors.toList()) );

        // 设备科审核确认
        if ("finish".equalsIgnoreCase(buttonKey)) {
            List<String> ids = new ArrayList<>();
            ids.add((dist.getId()));
            CommonService.updatebillFlow(ids, LocalDateTime.now(),true);
        }

        if ("dist".equalsIgnoreCase(buttonKey)) {   //开始配送
            //  开始配送就挂单
            if (applyAutoList.size() > 0) {

                //是否挂单
                if (ParameterUtils.isApplyHolder()) { //不对虚拟锁做任何操作，未拣货或者未完成拣货的配送明细还原到需求池中
                    if (distItems != null && distItems.size() > 0) {
                        List<DistItem> unCompleteDistItems = distItems.stream().filter(distItem -> StringUtils.isNotBlank(distItem.getApplyItemId())
                                && distItem.getSkuQty() >= distItem.getPickedSkuQty()).collect(Collectors.toList());
                        if (unCompleteDistItems != null && unCompleteDistItems.size() > 0) {
                            unCompleteDistItems.forEach(distItem -> {
                                double sumPickQty = distItemService.list(Wrappers.<DistItem>query().eq("apply_item_id", distItem.getApplyItemId())).stream().mapToDouble(DistItem::getPickedSkuQty).sum();
                                Optional<ApplyAuto> optionalApplyAuto = applyAutoList.stream().filter(applyAuto -> applyAuto.getRefApplyItemId().equals(distItem.getApplyItemId())).findFirst();
                                if (optionalApplyAuto.isPresent()) {
                                    ApplyAuto applyAuto = optionalApplyAuto.get();
                                    if (applyAuto.getSkuQtyApply() > sumPickQty) {
                                        applyAutoService.update(Wrappers.<ApplyAuto>update().set("ref_id", null).set("picked_sku_qty", sumPickQty).set("gmt_update",new Date()).set("bill_package_qty",UtilNum.getDouble((applyAuto.getSkuQtyApply()-sumPickQty)/distItem.getPackageRate()))
                                            .eq("id", applyAuto.getId()));
                                }
                                }
                            });
                        }
                    }
                } else { //删除所有配送明细对应的需求锁，不还原到需求池，默认该请领需求明细已全部完成。

                    Map<String, List<ApplyAuto>> applyAutoMap = applyAutoList
                            .stream().collect(Collectors.groupingBy(ApplyAuto::getWarehouseId));
                    for (String warehouseId : applyAutoMap.keySet()) {
                        List<String> busValues = applyAutoMap.get(warehouseId).stream().map(ApplyAuto::getRefApplyItemId).collect(Collectors.toList());
                        List<StockLock> virtualLockList = stockLockService.getVirtualLockList(LockBusType.APPLY, busValues, warehouseId);
                        if (virtualLockList != null) {
                            stockLockService.virtualUnlockList(LockBusType.APPLY, busValues, warehouseId);
                        }
                }
//                    applyAutoList.forEach(applyAuto -> {
//                        StockLock stockLock = stockLockService.getVirtualLock(LockBusType.APPLY, applyAuto.getRefApplyItemId(), applyAuto.getWarehouseId());
//                        if (stockLock != null) {
//                            stockLockService.virtualUnlock(LockBusType.APPLY, applyAuto.getRefApplyItemId(), applyAuto.getWarehouseId());
//                        }
//                    });
            }
            }

        }


        boolean endNode = flowContext.isEndNode();
        if (!endNode) {
            for (DistItem distItem : distItems) {
                if (StringUtils.isNotBlank(distItem.getApplyItemId())) {
                    //更新需求明细状态
                    CommonService.updateApplyItemStatus(distItem.getApplyItemId(), false, null);
                }
            }
            return;
        }

        List<PickItem> pickItems = pickItemMapper.selectList(Wrappers.<PickItem>query().eq("dist_id", dist.getId()));
        if (pickItems != null && pickItems.size() > 0) {
            //预算控制检查
            UtilBudget.checkBudgetControl(dist.getDeptId(),pickItems);

            List<WorkOrder> workOrders = convertDistToOrders(dist);
            List<WorkOrder> wos = workOrders;
           /* List<String> workOrderIds = wos.stream().map(WorkOrder::getId).collect(Collectors.toList());
            List<WorkOrderItem> workOrderItemList = workOrderItemMapper.selectList(Wrappers.<WorkOrderItem>query()
                    .in("work_order_id", workOrderIds));
            if (pickItems.size() != workOrderIds.size()) {
                throw new BusinessException("拣货明细数量【%s】与出库单明细数量【%s】不一致，转换出库单失败", pickItems.size(), workOrderIds.size());
            }*/
            List<String> woIds = wos.stream().map(WorkOrder::getId).collect(Collectors.toList());

            workOrderService.postBatch(woIds);

//            for (WorkOrder wo : wos) {
//                workOrderService.post(wo.getId());
//            }
            flowContext.setHandledMsg(String.format("科室配送审核完成，共生成%d个科室配送出库单", wos.size()));
            log.info("科室配送审核完成，共生成{}个科室配送出库单", wos.size());
            log.info("科室配送出库单分别为：{}", wos.stream().map(o -> o.getBusKey()).collect(Collectors.joining(",")));
        }
        CommonService.updateBusTableSnum("wm_dist",dist.getId());
//         出库记账,需求池数量重新计算,需求和拣货一直新增到历史表
        for (ApplyAuto applyAuto : applyAutoList) {
            if (StringUtils.isNotBlank(applyAuto.getRefApplyItemId())) {
                Double sumPickQty = distItemService.getObj(Wrappers.<DistItem>query().select("ifnull(sum(picked_sku_qty),0.0)").eq("apply_item_id", applyAuto.getRefApplyItemId()), v -> {
                    if (v == null) {
                        return 0.0;
                    }
                    return Double.valueOf(v.toString());
                });
                Double packageRate= distItemService.getpackageRate(applyAuto.getRefApplyItemId());
                applyAutoService.update(Wrappers.<ApplyAuto>update().set("picked_sku_qty", sumPickQty).set("picked_package_qty",sumPickQty/packageRate)
                        .eq("ref_apply_item_id", applyAuto.getRefApplyItemId()));
                if (StringUtils.isNotBlank(applyAuto.getRefApplyItemId())) {
                //更新需求明细状态
                CommonService.updateApplyItemStatus(applyAuto.getRefApplyItemId(), false, null);
            }
                if (applyAuto.getSkuQtyApply() <= sumPickQty || !ParameterUtils.isApplyHolder()) {
                ApplyAutoHistory applyAutoHistory = new ApplyAutoHistory();
                BeanUtils.copyProperties(applyAuto, applyAutoHistory);
                applyAutoHistory.setGmtComplete(LocalDateTime.now()).setStatus("1");
                applyAutoHistoryService.save(applyAutoHistory);
                applyAutoService.removeById(applyAuto);
//                    if (StringUtils.isNotBlank(applyAuto.getRefApplyItemId())) {
//                        applyItemService.update( Wrappers.<ApplyItem>update().set("status_dist",-1)
//                                .eq("id", applyAuto.getRefApplyItemId()));
//                    }
            }


        }
    }

    }


    @Override
    public void pdfPreview(String id, HttpServletResponse response) {
        response.setContentType(MediaType.APPLICATION_PDF_VALUE);

        Dist dist = super.getById(id);
        if (dist == null) {
            return;
        }

        PdfExportParams exportParams = new PdfExportParams()
                .setProject("武汉第六人民医院")
                .setTitle(String.format("科室配送出库单"))
                .setPerRowsOfGrid(10)
                .setPageDirection(PdfPageDirection.TRANSVERSE)
                .setWatermark("本公司")
                .setBarcodeText(dist.getBusKey());


        exportParams
                .addHeaderItem("配送单号", dist.getBusKey(), 8)
                .addHeaderItem("出库仓库", dist.getWarehouseName(), 8)
                .addHeaderItem("配送日期", dist.getBusDate(), 8)
                .addHeaderItem("接收科室", dist.getDeptName(), 8)
                .addHeaderItem("配送金额", dist.getAmount(), 8)
                .addHeaderItem("备注", dist.getRemark(), 8);

        exportParams.addGridColumn(new PdfExportGridIndexColumn("序号", 2))
                .addGridColumn("matrName", "材料名称", 6)
                .addGridColumn("matrSpec", "规格型号", 6)
                .addGridColumn("skuUnit", "单品单位", 2)
                .addGridColumn("skuQty", "需求数量", 2)
                .addGridColumn("pickedSkuQty", "拣货数量", 2)
                .addGridColumn("skuPrice", "单价", 2)
                .addGridColumn("amount", "小计(元)", 2);

        List<DistItem> distItems = distItemService.list(new QueryWrapper<DistItem>().eq("dist_id", id));
        exportParams.setGridData(distItems);

        exportParams.addFooterItem("库管员", dist.getBusUser(), 8)
                .addFooterItem("领用人", dist.getBusUser(), 8)
                .addFooterItem("送货人", "", 8);

        try {
            PdfExportUtils.export(response.getOutputStream(), exportParams);
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    @Override
    public List<WorkOrder> convertDistToOrders(Dist dist) {
        String distId = dist.getId();
        List<PickItem> pickItems = pickItemMapper.selectList(Wrappers.<PickItem>query().eq("dist_id", distId));
        if (pickItems.isEmpty()) {
            throw new BusinessException("拣货明细为空，转换科室配送出库单失败");
        }

        //根据库存里面的供应商分组，因为耗材供应商可能被修改
        List<String> stockIdList = pickItems.stream().map(PickItem::getStockId).collect(Collectors.toList());
        List<Stock> stockList = stockService.list(Wrappers.<Stock>query().in("id", stockIdList));
        if (stockList == null) {
            throw new BusinessException("拣货明细所对应的库存在系统中不存在，转换出库单失败");
        }
        if (stockList.size() != pickItems.size()) {
            throw new BusinessException("拣货明细数量【%s】与库存记录库存数量【%s】不一致，转换出库单失败", pickItems.size(), stockList.size());
        }

        //分组去重，条件：供应商，耗材，寄售，一物一码
        List<Stock> stockGroupList = UtilJava8.stockGroup(stockList);
        ArrayList<WorkOrder> orders = Lists.newArrayList();
        stockGroupList.stream().forEach(stockGroup -> {
            WorkOrderKey orderKey = new WorkOrderKey(stockGroup.getSupplierId(), stockGroup.getFlagConsignment(), stockGroup.getFlagOmoc());

            //符合该分组的所有库存
            List<Stock> stockAddList = UtilJava8.stockFilter(stockList, stockGroup);
            WorkOrder order = convertDemandItemsToOrder(orderKey, dist, UtilJava8.getWODistPickItems(stockAddList, pickItems));
            orders.add(order);
        });
        return orders;
    }

    private WorkOrder convertDemandItemsToOrder(WorkOrderKey orderKey,
                                                Dist dist, List<PickItem> pickItems) {

        BusinessException.throwValidFail("此方法已经废弃");
        String supplierId = orderKey.supplierId;
        Supplier supplier = supplierMapper.selectById(supplierId);
        if (supplier == null) {
            log.error("转换出库单失败，配送单号：{}，供应商 {} 不存在", dist.getBusKey(), supplierId);
            throw new BusinessException("转换科室配送出库单失败");
        }

        // 出库金额求和
        double sum = pickItems.stream().mapToDouble(o -> o.getAmount()).sum();

        WorkOrder wo = new WorkOrder();

        wo.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.OUT_ORDER_KEY))
                .setDirection(GlobalConsts.ORDER_DIRECTION_OUT)
                .setBusDate(new Date()).setBusUser(UserUtils.currentUser().getName()).setBusUserCode(UserUtils.currentUser().getWorkNo())
                .setBusType(null)
                .setFlagConsignment(orderKey.consignment).setFlagOmoc(orderKey.omoc)
                .setRefId(dist.getId()).setRefKey(dist.getBusKey()).setRefTable("wm_dist")
                .setSupplierId(supplier.getId()).setSupplierName(supplier.getName())
                .setWarehouseId(dist.getWarehouseId()).setWarehouseName(dist.getWarehouseName())
                .setDeliveryman(dist.getBusUser())
                .setAmount(sum)
                .setPurchaseOrderType(dist.getDistType())
                .setReagentTeamId(dist.getReagentTeamId())
                .setDeptId(dist.getDeptId()).setDeptName(dist.getDeptName())
                .setRemark(String.format("由配送单%s转换而来", dist.getBusKey()))
                .setFlowStatus(GlobalConsts.FLOW_END_VALUE).setFlowModifier(dist.getFlowModifier()).setFlowModified(dist.getFlowModified())

        ;
        workOrderMapper.insert(wo);

        List<String> stockIds = pickItems.stream().map(PickItem::getStockId).distinct().collect(Collectors.toList());
        if (stockIds.size()!=pickItems.size()) {
            throw new BusinessException("拣货明细和库存明细不一致，可能是由于数据错误");
        }
        List<Stock> stockList = stockService.list(Wrappers.<Stock>query().in("id", stockIds));
        Map<String, List<Stock>> stockMap = stockList.stream().collect(
                Collectors.groupingBy(Stock::getId));
        List<WorkOrderItem> orderItems = new ArrayList<>();
        for (PickItem pickItem : pickItems) {
            String stockId = pickItem.getStockId();
            Stock stock = stockMap.get(stockId).get(0);
            if (stock == null) {
                log.error("库存不存在，SN：{}，RFID：{}，UDI：{}，StockId：{}",
                        pickItem.getSn(), pickItem.getRfid(), pickItem.getUdi(), stockId);
                throw new BusinessException("库存不存在，可能是由于数据错误");
            }
            WorkOrderItem orderItem = new WorkOrderItem();
            String[] ignoreFields = Arrays.asList(DataEntity.class.getDeclaredFields())
                    .stream().map(field -> field.getName()).collect(Collectors.toList()).toArray(new String[]{});
            BeanUtils.copyProperties(stock, orderItem, ignoreFields);
            orderItem.setStockId(stockId);
            orderItem.setWorkOrderId(wo.getId()).setRemark(String.format("由配送单 %s 转换而来", dist.getBusKey()));

            orderItem.setRefBusItemId(pickItem.getId());
            orderItems.add(orderItem);
        }
        workOrderItemService.saveOrUpdateBatch(orderItems);

        return wo;
    }

    /**
     * 根据订单自动转换配送单
     *
     * @param workOrder
     */
    @Override
    public Dist autoChangeDist(WorkOrder workOrder) {
        workOrder = workOrderService.getById(workOrder.getId()); //再请求一遍
        String refDistId = workOrder.getRefDistId();
        if (refDistId != null && !"0".equalsIgnoreCase(refDistId)) {
            throw new BusinessException(String.format("该订单已经转换过配送单，配送单号为%s，不能重复转换", refDistId));
        }
        // 试剂类型标识
        boolean isReagent = PurchaseType.REAGENT.getKey().equals(workOrder.getPurchaseOrderType());

        // 根据不同条件查询送货明细
        List<WorkOrderItem> workOrderItems = workOrderItemMapper.selectList(Wrappers.<WorkOrderItem>query().eq("work_order_id", workOrder.getId()));
        if (workOrderItems.isEmpty()) {
            throw new BusinessException("送货明细为空，转换配送单失败");
        }

        Dist dist = new Dist();
        //判断如果时手动入库和其他
        if (WorkOrderType.IN_MANUAL.equals(workOrder.getBusType())) {
            Dept dept = deptService.getById(workOrder.getDeptId()); //需求科室信息
            if (dept == null) { throw new BusinessException("未找到需求科室"); }
            if (StringUtils.isBlank(dept.getWarehouseId())) { throw new BusinessException("需求科室未设置对应仓库"); }
            dist.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.WM_DIST_KEY))
                    .setBusDate(new Date()).setBusUser(UserUtils.currentUser().getName())
                    .setDeptId(workOrder.getDeptId()).setDeptName(workOrder.getDeptName())
                    .setWarehouseId(workOrder.getWarehouseId()).setWarehouseName(workOrder.getWarehouseName())
                    .setAmount(workOrder.getAmount())
                    .setReagentTeamId(workOrder.getReagentTeamId())
                    .setDistType(UtilCommon.getStr(workOrder.getPurchaseOrderType(),"matr"))
                    .setRemark(workOrder.getRemark() + String.format("--由入库单%s转换而来", workOrder.getBusKey()));
            // 判断采购入库转配送单状态参数 手动入库暂时也有这个参数来
            if (GlobalConsts.FLOW_PICKING_VALUE.equals(ParameterUtils.getString("in_order_change_dist"))) {
                // 配送单转为拣货中
                dist.setStatusPick(GlobalConsts.YES).setPicker(UserUtils.currentUser().getName()).setFlowStatus(GlobalConsts.FLOW_PICKING_VALUE);
                dist.setPickDate(new Date()).setFlowModified(LocalDateTime.now()).setFlowModifier(UserUtils.currentUser().getName());
            }
            baseMapper.insert(dist);

            List<PickDTO> pickList = new ArrayList<>();
            for (WorkOrderItem workOrderItem : workOrderItems) {
                DistItem distItem = new DistItem();
                distItem.setDistId(dist.getId())
                        .setSkuPrice(workOrderItem.getSkuPrice())
                        .setMatrId(workOrderItem.getMatrId()).setMatrName(workOrderItem.getMatrName()).setMatrSpec(workOrderItem.getMatrSpec())
                        .setPackageUnit(workOrderItem.getPackageUnit()).setPackageQty(workOrderItem.getPackageQty())
                        .setSkuUnit(workOrderItem.getSkuUnit()).setSkuPrice(workOrderItem.getSkuPrice()).setSkuQty(workOrderItem.getSkuQty())
                        .setPickedSkuQty(0.0)
                        .setPackageRate(workOrderItem.getSkuQty() / workOrderItem.getPackageQty())
                        .setAmount(workOrderItem.getAmount())
                        .setRemark(String.format("由入库单%s转换而来", workOrder.getBusKey()));
                distItemService.save(distItem);
                // 判断采购入库转配送单状态参数
                if (GlobalConsts.FLOW_PICKING_VALUE.equals(ParameterUtils.getString("in_order_change_dist"))) {
                    List<Stock> stockItems = stockService.list(Wrappers.<Stock>query().eq("line_id", workOrderItem.getLineId()));
                    // 增加拣货明细
                    for (Stock stockItem : stockItems) {
                        PickDTO pickDTO = new PickDTO();
                        pickDTO.setDistId(dist.getId());
                        pickDTO.setUniqueCode(stockItem.getSn());
                        pickList.add(pickDTO);
                    }
                }
            }
            this.pickBatch(pickList);
        }else {
        Order order = orderService.getById(workOrder.getPurchaseOrderId());
        if (order == null) {
            throw new BusinessException("采购单为空，转换配送单失败");
        }

        Dept dept = deptService.getById(order.getDeptIdDemand()); //需求科室信息
        if (dept == null) { throw new BusinessException("未找到需求科室"); }
        if (StringUtils.isBlank(dept.getWarehouseId())) { throw new BusinessException("需求科室未设置对应仓库"); }
        Apply apply = new Apply();
        if (StringUtils.isNotBlank(order.getRefId())) {
            Demand demand = demandService.getById(order.getRefId());
            if (demand != null) {
                apply = applyService.getById(demand.getRefId());
            }
        }
        if (!isReagent && (apply == null || StringUtils.isBlank(apply.getBusKey()))) { throw new BusinessException("未找到相关请领单据，请制作手工配送单"); }

        // 根据耗材类型动态设置请领单字段
        if (isReagent) {
            if (apply != null) {
                dist.setApplyKey(apply.getBusKey()).setApplyDate(apply.getBusDate());
            }
        } else {
            dist.setApplyKey(apply.getBusKey()).setApplyDate(apply.getBusDate());
        }
        dist.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.WM_DIST_KEY))
                .setBusDate(new Date()).setBusUser(UserUtils.currentUser().getName()).setBusUserCode(UserUtils.currentUser().getWorkNo())
//                .setApplyId(order.getId()).setApplyKey(apply.getBusKey()).setApplyDate(apply.getBusDate())
                .setDeptId(order.getDeptIdDemand()).setDeptName(order.getDeptNameDemand())
                .setWarehouseId(workOrder.getWarehouseId()).setWarehouseName(workOrder.getWarehouseName())
                .setAmount(workOrder.getAmount())
                .setReagentTeamId(workOrder.getReagentTeamId())
                .setRemark(String.format("由入库单%s转换而来", workOrder.getBusKey())).setDistType(UtilCommon.getStr(workOrder.getPurchaseOrderType(),"matr"));
        // 判断采购入库转配送单状态参数
        if (GlobalConsts.FLOW_PICKING_VALUE.equals(ParameterUtils.getString("in_order_change_dist"))) {
            // 配送单转为拣货中
            dist.setStatusPick(GlobalConsts.YES).setPicker(UserUtils.currentUser().getName()).setFlowStatus(GlobalConsts.FLOW_PICKING_VALUE);
            dist.setPickDate(new Date()).setFlowModified(LocalDateTime.now()).setFlowModifier(UserUtils.currentUser().getName());
        }
        baseMapper.insert(dist);

        //更新因自动请领产生的二级库配送需求单对应的RefId
        List<ApplyAuto> applyAutos = applyAutoService.list(new QueryWrapper<ApplyAuto>().eq("ref_order_id", workOrder.getPurchaseOrderId()));
        if (applyAutos != null && applyAutos.size() > 0) {
            applyAutos.stream().forEach(applyAuto -> {
                applyAuto.setRefId(dist.getId());
            });
            applyAutoService.saveOrUpdateBatch(applyAutos);
        }

        for (WorkOrderItem workOrderItem : workOrderItems) {
            DistItem distItem = new DistItem();
            BeanUtils.copyProperties(workOrderItem, distItem);
            distItem.setId(null);
            // 根据耗材类型动态设置请领单字段
            if (isReagent) {
                if (apply != null) {
                    distItem.setApplyId(apply.getId());
                }
            } else {
                distItem.setApplyId(apply.getId());
            }
            distItem.setDistId(dist.getId())
                    .setSkuPrice(workOrderItem.getSkuPrice())
                    .setMatrId(workOrderItem.getMatrId()).setMatrName(workOrderItem.getMatrName()).setMatrSpec(workOrderItem.getMatrSpec())
                    .setPackageUnit(workOrderItem.getPackageUnit()).setPackageQty(workOrderItem.getPackageQty())
                    .setSkuUnit(workOrderItem.getSkuUnit()).setSkuPrice(workOrderItem.getSkuPrice()).setSkuQty(workOrderItem.getSkuQty())
                    .setPickedSkuQty(0.0)
                    .setPackageRate(workOrderItem.getSkuQty() / workOrderItem.getPackageQty())
                    .setAmount(workOrderItem.getAmount())
                    .setRemark(String.format("由入库单%s转换而来", workOrder.getBusKey()));
            distItemService.save(distItem);
            // 判断采购入库转配送单状态参数
            if (GlobalConsts.FLOW_PICKING_VALUE.equals(ParameterUtils.getString("in_order_change_dist"))) {
                List<Stock> stockItems = stockService.list(Wrappers.<Stock>query().eq("line_id", workOrderItem.getLineId()));
                // 增加拣货明细
                for (Stock stockItem : stockItems) {
                    this.pick(dist.getId(), stockItem.getSn());
                }
            }
        }
        }
        //赋值生成的配送单号
        WorkOrder workOrder1 = new WorkOrder();
        workOrder1.setId(workOrder.getId());
        workOrder1.setRefDistId(dist.getId());
        workOrderService.updateById(workOrder1);

        return dist;
    }

    @Override
    public Map getDistByKey(String distKey) {
        Dist dist = baseMapper.selectOne(Wrappers.<Dist>query().eq("bus_key", distKey));
        if (dist == null) {
            throw new BusinessException("未找到配送单号：" + distKey);
        }
        return getDistInfo(dist);
    }

    @Override
    public Map getDistById(String distId) {
        Dist dist = baseMapper.selectById(distId);
        if (dist == null) {
            throw new BusinessException("未找到配送ID：" + distId);
        }
        return getDistInfo(dist);
    }

    private Map getDistInfo(Dist dist) {
        Map result = new HashMap();
        result.put("dist", dist);
        List<DistItem> distItems = distItemService.list(
                Wrappers.<DistItem>query().eq("dist_id", dist.getId()));
        result.put("distItems", distItems);

        List<PickItem> pickItems = pickItemMapper.selectList(
                Wrappers.<PickItem>query().eq("dist_id", dist.getId()));
        result.put("pickItems", pickItems);
        return result;
    }

    @Override
    public Map getDistSchedule() {
        Map result = new HashMap();
        result.put("dists", baseMapper.getDistSchedule());
        result.put("distItems", baseMapper.getDistItemSchedule());
        return result;
    }

    @Override
    public Map mobilePick(String distId, String uc) {
        this.pick(distId, uc);
        Dist dist = baseMapper.selectById(distId);
        if (dist.getFlowStatus() != "picking") {
            dist.setFlowStatus("picking");
            baseMapper.updateById(dist);
        }
        return getDistInfo(dist);
    }

    @Override
    public void updateReceiver(Map para) {
        String fileName = Md5Utils.getRandomCode(16) + ".jpg";
        String rPath = resPath + "signature\\";
        String vPath = "res/signature/" + fileName;
        FileUtils.mkdirs(rPath);
        ImageUtils.fromBase64(para.get("signature").toString(), rPath + fileName);
        this.update(Wrappers.<Dist>update()
                .set("receiver", para.get("receiver"))
                .set("dept_signature", vPath)
                .eq("id", para.get("id")));
    }

    @Override
    public Integer findThisWeekDistCount() {
        Date beginDate = DateUtils.parse(DateFormatUtils.format(DateUtils.getFirstDayOfWeek(new Date()), "yyyy-MM-dd 00:00:00"));
        Integer count = this.baseMapper.selectCount(Wrappers.<Dist>query().gt("gmt_create", beginDate));
        return count;
    }

    @Override
    public Integer findThisWeekDeliveryCount() {
        Date beginDate = DateUtils.parse(DateFormatUtils.format(DateUtils.getFirstDayOfWeek(new Date()), "yyyy-MM-dd 00:00:00"));
        Integer count = this.baseMapper.selectCount(Wrappers.<Dist>query().gt("gmt_create", beginDate)
                .eq("flow_status", "end")
        );
        return count;
    }

    @Override
    public List<Map> listForPDA(String busKey) {
        QueryWrapper<DistVO> wrapper = new QueryWrapper<>();
        wrapper.nested(i -> i.eq("status_pick", GlobalConsts.YES).or().in("flow_status", Arrays.asList("start","picking")))
//                .and(o -> o.eq("picker", UserUtils.currentUser().getName()).or().isNull("picker"))
        ;
        if (StringUtils.isNotBlank(busKey)) {
            wrapper.eq("bus_key", busKey);
        }
        wrapper.orderByAsc("gmt_create");
        List<Map> list = this.baseMapper.listForPDA(wrapper);
        if (StringUtils.isNotBlank(busKey) && (list == null || list.size() < 1)){
            throw  new BusinessException("配送单【%s】已被移除或者不可操作",busKey);
        }
        return list;
    }

    /**
     * 订单标识，用来作为转换订单时的标识
     */
    @EqualsAndHashCode
    @AllArgsConstructor
    private class WorkOrderKey {
        private String supplierId;
        private boolean consignment;
        private boolean omoc;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pickBatch(List<PickDTO> pickDTOs) {
        if (pickDTOs == null || pickDTOs.size() < 1) return;
/*        pickDTOs.forEach(ob -> {
            this.pick(ob.getDistId(), ob.getUniqueCode());
        });*/




        Dist dist = this.getById(pickDTOs.get(0).getDistId());
        if (dist == null) {
            throw new BusinessException("配送单不存在");
        }
        ArrayList<PickItem> picksList = new ArrayList<>();
        List<Stock> stocks = stockLockService.lockBatch(LockBusType.DIST,
                dist.getId(),
                dist.getWarehouseId(),
                String.format("配送单 %s 拣货锁定",
                dist.getBusKey()),pickDTOs.stream().map(PickDTO::getUniqueCode).collect(Collectors.toList()),dist.getSourceType()
        );

        Map<String, List<Matr>> matrMap = SingleService.inst.matrService.list(Wrappers.<Matr>query().in("id",stocks.stream().map(Stock::getMatrId).collect(Collectors.toList())))
                .stream().collect(Collectors.groupingBy(Matr::getId));
        //是否禁用耗材校验--配送时批量拣货
        matrPassUtil.ckeckMatrPass("dist", new ArrayList<>(matrMap.keySet()));

        // 先查询现有的拣货明细
        List<PickItem> exist = pickItemService.list(Wrappers.<PickItem>query().eq("dist_id", dist.getId()));
        if (CollectionUtils.isEmpty(exist)) {
            // 更新配送单耗材类型
            String distType = PurchaseType.MATR.getKey();
            for (String key : matrMap.keySet()) {
                List<Matr> value = matrMap.get(key);
                if (value.stream().anyMatch(m -> PurchaseType.REAGENT.getKey().equals(m.getBaseType()))) {
                    dist.setDistType(PurchaseType.REAGENT.getKey());
                    distType = PurchaseType.REAGENT.getKey();
                    break;
                }
            }
            dist.setDistType(distType);
        } else {
            // 不同耗材类型不允许拣货
            final String distType = dist.getDistType();
            for (String key : matrMap.keySet()) {
                List<Matr> value = matrMap.get(key);
                if (value.stream().anyMatch(m -> !distType.equals(m.getBaseType()))) {
                    throw new BusinessException("选择的耗材类型与配送单的耗材类型不一致，不允许拣货");
                }
            }
        }

        // 请领是否锁库存
        boolean applyLock = ParameterUtils.isApplyLockStock();
        stocks.forEach(stock -> {
            CommonService.checkStock(stock, null);
            DistItem distItem = pickRefDistItem(stock, dist.getId());
            // 增加拣货明细
            PickItem pickItem = new PickItem();
            BeanUtils.copyProperties(stock, pickItem);
            pickItem.setId(null);
            pickItem.setDistId(dist.getId()).setDistItemId(distItem.getId()).setStockId(stock.getId())
                    .setMatrId(stock.getMatrId()).setMatrName(stock.getMatrName()).setMatrSpec(stock.getMatrSpec())
                    .setPackageUnit(stock.getPackageUnit()).setPackageRate(stock.getSkuQty() / stock.getPackageQty()).setPackageQty(stock.getPackageQty())
                    .setSkuUnit(stock.getSkuUnit()).setSkuPrice(stock.getSkuPrice()).setSkuQty(stock.getSkuQty())
                    .setAmount(stock.getAmount()).setCertificateNo(stock.getCertificateNo()).setMfgName(stock.getMfgName())
                    .setLot(stock.getLot()).setExpDate(stock.getExpDate()).setMfgDate(stock.getMfgDate())
                    .setSn(stock.getSn()).setUdi(stock.getUdi()).setRfid(stock.getRfid()).setUcType(UniqueCodeType.SN.name())
                    .setSupplierId(stock.getSupplierId()).setSupplierName(stock.getSupplierName())
                    .setRemark(String.format("配送单 %s 拣货", dist.getBusKey()));
            if (pickItem.getPackageRate() == null) {
                pickItem.setPackageRate(1d);
            }
            // pickItemMapper.insert(pickItem);
            picksList.add(pickItem);
            //更新需求明细状态
            CommonService.updateApplyItemStatus(distItem.getApplyItemId(), false, null);

            //拣货解锁虚拟锁
            if (applyLock) {
                List<DistItem> distItems = distItemService.list(new QueryWrapper<DistItem>().eq("dist_id", dist.getId()).eq("matr_id", stock.getMatrId()).isNotNull("apply_item_id"));
                if (distItems != null && distItems.size() > 0) {
                    unLockApplyVirtual(stock.getSkuQty(), distItems.stream().map(DistItem::getApplyItemId).collect(Collectors.toList()), dist.getWarehouseId());
                }
            }
        });
        pickItemService.saveOrUpdateBatch(picksList);
        //更新-配送单拣货数量 、拣货和需求比对
        DistDTO distDTO = baseMapper.getDistAmountAndPick(dist.getId());
        Double demandsSum = baseMapper.getDistDemand(dist.getId());
        String pickAndDemand = UtilNum.getString(distDTO.getPickQty()) + "-/-" + UtilNum.getString(demandsSum);
        baseMapper.calculateDistInfo(dist.getId(), pickAndDemand, distDTO.getAmount(), dist.getDistType());
    }

    @Override
    public DistVO findByIdForPDA(String id) {
        return this.baseMapper.findByIdForPDA(id);
    }

    @Override
    public DistVO findBy(String key, String value) {
        return this.baseMapper.findBy(key,value);
    }


    //校验开单数量
    public void checkBillBatch(List<Stock> stocks,Dist dist) {
        if (StringUtils.isBlank(dist.getSourceType())) return ;
        if (!GlobalConsts.DistTransferSourceType.DEPT_APPLY_AUTO.equals(dist.getSourceType()) && !GlobalConsts.DistTransferSourceType.DEPT_APPLY.equals(dist.getSourceType())) return ;
        if (stocks == null || stocks.size() < 0) return;

        //此处不过滤 apply_item_id 因为自动需求中没有关联请领信息的
        List<DistItem> distItems = distItemService.list(Wrappers.<DistItem>query().in("dist_id", dist.getId()));
        if (distItems == null || distItems.size() < 0)  throw new  BusinessException("该单据没有需求，不可进行拣货操作");

        //锁定库存，按照耗材分组
        Map<String,List<Stock>> stockGroupByMatr = stocks.stream().collect(Collectors.groupingBy(Stock::getMatrId));

        //配送需求，按照耗材分组
        Map<String,List<DistItem>> distItemsGroupByMatr = distItems.stream().collect(Collectors.groupingBy(DistItem::getMatrId));

        stockGroupByMatr.keySet().forEach(matrId -> {
            List<Stock> stockMatrList = stockGroupByMatr.get(matrId);
            Stock stockOne = stockMatrList.get(0);

            //是否存在配送需求
            List<DistItem> distItemMatrList = distItemsGroupByMatr.get(matrId);
            if (distItemMatrList == null || distItemMatrList.size() < 1)throw new BusinessException("拣货失败，耗材[%s]在配送需求中不存在",stockOne.getMatrName());


            //该耗材拣货数量是否已经超过开单数量
            double pickSku = UtilNum.getDouble(stockMatrList.stream().mapToDouble(Stock::getSkuQty).sum());
            double pickCanSku = 0;
            for(DistItem distItem : distItemMatrList){
                pickCanSku+=(distItem.getBillPackageQty()*distItem.getBillPackageRate() - distItem.getPickedSkuQty());
            }
            if (pickSku > pickCanSku )throw new BusinessException("拣货失败，耗材[%s]拣货总单品数量[%s]已经超出可开单单品数量[%s]，请减少拣货数量",stockOne.getMatrName(),pickSku,pickCanSku);
        });
    }




}
